﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using SonarSnitch.Business.Entity;
using System.Configuration;

namespace SonarSnitch.Business.Process
{
    public class SonarService
    {
        /// <summary>
        /// Identifica a isntância do sonar
        /// </summary>
        private string servidor = ConfigurationManager.AppSettings["servidor"].ToString();
        
        /// <summary>
        /// Métricas básicas que serão monitoradas
        /// </summary>
        private string metricas = ConfigurationManager.AppSettings["metricas"].ToString();

        /// <summary>
        /// Dispara a requisição para o sonar esperando um resultado json e entrega o texto da requisição
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        private string CarregarRequisicaoJson(string uri)
        {
            var request = WebRequest.Create(uri);
            request.ContentType = "application/json; charset=utf-8";

            string text;
            var response = (HttpWebResponse)request.GetResponse();
            using (var sr = new StreamReader(response.GetResponseStream()))
            {
                text = sr.ReadToEnd();
            }

            return text;
        }

        /// <summary>
        /// Carrega todos os projetos do Sonar
        /// </summary>
        /// <returns></returns>
        public IList<Projeto> ListarProjetos()
        {
            string text = CarregarRequisicaoJson(string.Format("{0}/api/resources?metrics={1}&format=json", servidor, metricas));
            
            List<Projeto> projetos = new List<Projeto>();
            JArray jsProjetos = JArray.Parse(text);
            foreach (var item in jsProjetos)
            {
                projetos.Add(new Projeto(item));
            }

            return projetos;
        }

        /// <summary>
        /// Carrega as métricas base de um projeto em um intervalo de tempo 
        /// </summary>
        /// <returns></returns>
        public Projeto CarregarMetricasPorTempo(Projeto projeto, DateTime inicio, DateTime termino)
        {
            projeto.Intervalos.Clear();

            string text = CarregarRequisicaoJson(string.Format("{0}/api/timemachine?resource={1}&metrics={2}&fromDateTime={3}T00:00:00&toDateTime={4}T23:59:59&format=json", 
                servidor, 
                projeto.Codigo, 
                metricas,
                inicio.ToString("yyyy-MM-dd"),
                termino.ToString("yyyy-MM-dd")));

            JArray jsRequest = JArray.Parse(text);

            JArray jsMetricas = JArray.FromObject(jsRequest[0]["cols"]);
            JArray jsMedicoes = JArray.FromObject(jsRequest[0]["cells"]);
            

            for (int i = 0; i < jsMetricas.Count; i++)
            {
                var intervalo = new Intervalo();
                
                intervalo.Metrica = jsMetricas[i]["metric"].Value<string>();
                if (intervalo.Metrica.Equals("codigo_regional"))
                {
                    continue;
                }
                
                var intervaloInicial = jsMedicoes.FirstOrDefault();
                if(intervaloInicial == null)
                {
                    intervalo.Avaliacao = AvaliacaoEnum.Inexistente;
                }
                else
                {
                    intervalo.Inicio = intervaloInicial["d"].Value<DateTime>();
                    var valoresInicio = JArray.FromObject(intervaloInicial["v"]);
                    intervalo.ValorInicial = valoresInicio[i].Value<float?>().HasValue ? valoresInicio[i].Value<float?>().Value : 0;
                    var intervaloFinal = jsMedicoes.Last();
                    intervalo.Termino = intervaloFinal["d"].Value<DateTime>();
                    if (intervalo.Inicio.Equals(intervalo.Termino))
                    {
                        intervalo.Avaliacao = AvaliacaoEnum.Inalterada;
                    }
                    else
                    {
                        var valoresTermino = JArray.FromObject(intervaloFinal["v"]);
                        intervalo.ValorFinal = valoresTermino[i].Value<float?>().HasValue ? valoresTermino[i].Value<float?>().Value : 0;

                        if (intervalo.ValorInicial > intervalo.ValorFinal)
                        {
                            intervalo.Avaliacao = AvaliacaoEnum.Negativa;
                        }
                        else if (intervalo.ValorInicial < intervalo.ValorFinal)
                        {
                            intervalo.Avaliacao = AvaliacaoEnum.Positiva;
                        }
                        else
                        {
                            intervalo.Avaliacao = AvaliacaoEnum.Inalterada;
                        }
                    }
                }

                projeto.Intervalos.Add(intervalo);
            }
            
            return projeto;
        }

        /// <summary>
        /// Lista todos os projetos do Sonar e filtra por código da regional
        /// </summary>
        /// <param name="codigoRegional"></param>
        /// <returns></returns>
        public IList<Projeto> ListarProjetos(string manualMeasure, string valor)
        {
            return ListarProjetos(ListarProjetos(), manualMeasure, valor);
        }

        /// <summary>
        /// Filtra dentre os projetos passados quais são da regional informada
        /// </summary>
        /// <param name="projetos"></param>
        /// <param name="codigoRegional"></param>
        /// <returns></returns>
        public IList<Projeto> ListarProjetos(IList<Projeto> projetos, string manualMeasure, string valor)
        {
            return projetos.Where(p => p.Configurado(manualMeasure, valor)).ToList();
        }

        /// <summary>
        /// Recupera um projeto com base no ID
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Projeto GetProjeto(string id)
        {
            try
            {
                string text = CarregarRequisicaoJson(string.Format("{0}/api/resources?resource={1}&format=json", servidor, id));

                JArray jsProjeto = JArray.Parse(text);
                return new Projeto(jsProjeto.First());
            }
            catch (WebException erro)
            {
                if (erro.Status == WebExceptionStatus.ProtocolError)
                {
                    return null;
                }
                else
                {
                    throw erro;
                }
            }
        }
    }
}
